#include "Map.h"

using namespace std;

//----------------------------------------------------------------------
//CGrNode Construction and Destruction
//----------------------------------------------------------------------

CGrNode::CGrNode()
{
	m_count=0;
	m_density=0;
	m_size=0;
	m_cluster=0;
	m_freq=0;
	m_nextNode=NULL;

}

CGrNode::~CGrNode()
{
}

//----------------------------------------------------------------------
//CMap Construction and Destruction
//----------------------------------------------------------------------
CMap::CMap()
{
	int ii;
	
	for(ii=0;ii<MAXNUMINDEXMAP;ii++)
		m_indexMap[ii]=NULL;
	
	for(ii=0;ii<MAXNUMDENSITYMAP;ii++)
		m_densityMap[ii]=NULL;

	m_grPixels=0; //total number of data pixels in input map
	m_maxPixels=0;
	m_grNum=0;	//total number of grains in input map

	grainList=new CGrNode*[MAXGRNUM];
	
	for (ii=0;ii<MAXGRNUM;ii++)
		grainList[ii]=NULL;
	
	MakeIndexMap();
	

}

CMap::CMap(int* mapHeight, int* mapWidth)
{
	int ii;
	
	for(ii=0;ii<MAXNUMINDEXMAP;ii++)
		m_indexMap[ii]=NULL;
	
	for(ii=0;ii<MAXNUMDENSITYMAP;ii++)
		m_densityMap[ii]=NULL;

	m_grPixels=0; //total number of data pixels in input map
	m_maxPixels=0;
	m_grNum=0;	//total number of grains in input map

	grainList=new CGrNode*[MAXGRNUM];
	
	for (ii=0;ii<MAXGRNUM;ii++)
		grainList[ii]=NULL;
	
	MakeIndexMap();
	
	*mapHeight=m_height;
	*mapWidth=m_width;

}

CMap::~CMap()
{
	int ii;

	for (ii=0;ii<MAXGRNUM;ii++)
		if (grainList[ii]!=NULL) delete grainList[ii];
	delete grainList;
	
	for (ii=0;ii<MAXNUMINDEXMAP;ii++)
		if (m_indexMap[ii]!=NULL) DeleteIndexMap(m_indexMap[ii]);
	for (ii=0;ii<MAXNUMDENSITYMAP;ii++)
		if (m_densityMap[ii]!=NULL) DeleteDensityMap(m_densityMap[ii]);
}

//----------------------------------------------------------------------
//CMap Member functions
//----------------------------------------------------------------------

char* CMap::GetMapName()
{
	return m_mapName;
}

char* CMap::GetFileName()
{
	return m_fileName;
}

int CMap::GetHeight()
{
	return m_height;
}

int CMap::GetWidth()
{
	return m_width;
}

int CMap::GetGrainAmount()
{
	return m_grNum;
}

int CMap::GetGrainPixels()
{
	return m_grPixels;
}

int CMap::GetMaxPixels()
{
	return m_maxPixels;
}

INDEXMAP CMap::MakeIndexMap()
{
	int ii, jj;
	char* tempStr;

	//read input file
	cout<<"Input a filename : ";
	cin>>m_fileName;
	strcpy(m_mapName,m_fileName);
	tempStr=strtok(m_mapName,".");
	tempStr=NULL;
	//cout<<m_mapName<<endl; pause();
	//read INPUT DATA (ASCII File)
	char temp[256];

	ifstream BaseMap(m_fileName);
	
	if (!BaseMap)
	{
		cout<<"There is no file."<<endl;
		exit(0);
	}		

	BaseMap>>temp; BaseMap>>m_width;
	BaseMap>>temp; BaseMap>>m_height;
	BaseMap>>temp; BaseMap>>temp;
	BaseMap>>temp; BaseMap>>temp;
	BaseMap>>temp; BaseMap>>temp;
	BaseMap>>temp; BaseMap>>temp;

	cout<<" Height of the input map : "<<m_height<<endl;
	cout<<" Width of the input map :  "<<m_width<<endl;

	//make index map
//	m_indexMap[INDEX]= new int* [m_width];	
//	for (ii=0;ii<m_width; ii++) m_indexMap[INDEX][ii]= new int [m_height];
	m_indexMap[INDEX]=MakeNULLIndexMap();	
	
	for (jj=0;jj<m_height; jj++)
		for (ii=0;ii<m_width; ii++)
		{
			BaseMap>>m_indexMap[INDEX][ii][jj];
			if (m_indexMap[INDEX][ii][jj]!=NODATA) 
			{	
				m_grPixels++;
				if (grainList[m_indexMap[INDEX][ii][jj]]==NULL)
				{
					grainList[m_indexMap[INDEX][ii][jj]]= new CGrNode();
					grainList[m_indexMap[INDEX][ii][jj]]->m_count++;
					m_grNum++;
				}
				else grainList[m_indexMap[INDEX][ii][jj]]->m_count++;
			}
		}

	BaseMap.close();
	
	return m_indexMap[INDEX];
}

INDEXMAP CMap::MakeNULLIndexMap()
{
	int ii, jj;
	
	INDEXMAP map;
	
	map= new int* [m_width];
	for (ii=0;ii<m_width; ii++) map[ii]= new int [m_height];
	for (ii=0;ii<m_width; ii++)
		for (jj=0;jj<m_height; jj++)
			map[ii][jj]=NODATA;
	
	return map;
}

DENSITYMAP CMap::MakeNULLDensityMap()
{
	int ii, jj;
	
	DENSITYMAP map;
	
	map= new double* [m_width];
	for (ii=0;ii<m_width; ii++) map[ii]= new double [m_height];
	for (ii=0;ii<m_width; ii++)
		for (jj=0;jj<m_height; jj++)
			map[ii][jj]=NODATA;
	
	return map;
}

void CMap::DeleteIndexMap(INDEXMAP map)
{
	int ii;
	
	if (map!=NULL)
	{
		for (ii=0;ii<m_width; ii++) delete map[ii];
		delete map;
	}
}

void CMap::DeleteDensityMap(DENSITYMAP map)
{
	int ii;
	
	if (map!=NULL)
	{
		for (ii=0;ii<m_width; ii++) delete map[ii];
		delete map;
	}
}

INDEXMAP CMap::MakeMaxCircleMap()
{
	int ii, jj;
	int cent_x, cent_y;
	double sqradius;
	int area;
	double dist;
	int count;
	
	//make maxcircle map
	area=m_grPixels;	
	cent_x=m_width/2;
	cent_y=m_height/2;
	sqradius=area/3.141592;
	
	count=0;
	m_indexMap[MAXIMUM]= new int* [m_width];
	for (ii=0;ii<m_width; ii++) m_indexMap[MAXIMUM][ii]= new int [m_height];
	for (ii=0;ii<m_width; ii++)
		for (jj=0;jj<m_height; jj++)
		{
			dist=pow((-(cent_x)+ii),2.0)+pow((-(cent_y)+jj),2.0);
			if (dist<=sqradius) 
			{
				m_indexMap[MAXIMUM][ii][jj]=0;
				count++;
			}
			else m_indexMap[MAXIMUM][ii][jj]=NODATA;
		}
	m_maxPixels=count;

	//make maxdensity map
	//maxdensity=MakeDensityMap();
			
	return m_indexMap[MAXIMUM];
}

INDEXMAP CMap::IndexMapType(int mapType, char* strMapType)
{
	INDEXMAP tempMap;
	char tempType[256];
	
	switch(mapType)
	{
		case INDEX : 
			{
				if (m_indexMap[mapType]==NULL)
				{ 
					tempMap=MakeIndexMap();
				}
				else
					tempMap=m_indexMap[mapType];
				strcpy(tempType,"index");
			}
			break;
		case MAXIMUM :
			{
				if (m_indexMap[mapType]==NULL)
				{ 
					tempMap=MakeMaxCircleMap();
				}
				else
					tempMap=m_indexMap[mapType];
				strcpy(tempType,"maximum");
			}
			break;
		default :
			{ 
				cout<<"There is no specific index map type."<<endl;
				if ((m_indexMap[mapType]==NULL)||(mapType>=MAXNUMINDEXMAP))
				{ 
					cout<<"Error: there is no index map."<<endl;
					exit(0);
				}
				else
				{
					tempMap=m_indexMap[mapType];
					strcpy(tempType,"unknown");
				}
			}
	}

	if (strMapType!=NULL) strcpy(strMapType,tempType);

	return tempMap;
}

DENSITYMAP CMap::DensityMapType(int mapType, char* strMapType)
{
	DENSITYMAP tempMap;
	char tempType[256];
	
	switch(mapType)
	{
		case SIZE : 
			{
				tempMap=m_densityMap[SIZE];
				strcpy(tempType,"size");
			}
			break;
		case CLUSTER :
			{
				tempMap=m_densityMap[CLUSTER];
				strcpy(tempType,"cluster");
			}
			break;
		case DENSITY :
			{
				tempMap=m_densityMap[DENSITY];
				strcpy(tempType,"density");
			}
			break;
		case FREQ : 
			{
				tempMap=m_densityMap[FREQ];
				strcpy(tempType,"freq");
			}
			break;
		case MAX : 
			{
				tempMap=m_densityMap[MAX];
				strcpy(tempType,"max");
			}
			break;
		case HOR : 
			{
				tempMap=m_densityMap[HOR];
				strcpy(tempType,"hor");
			}
			break;
		case VER : 
			{
				tempMap=m_densityMap[VER];
				strcpy(tempType,"ver");
			}
			break;
		default :
			{ 
				cout<<"There is no specific density map type."<<endl;
				if ((m_densityMap[mapType]==NULL)||(mapType>=MAXNUMDENSITYMAP))
				{ 
					cout<<"Error: there is no density map."<<endl;
					exit(0);
				}
				else
				{
					tempMap=m_densityMap[mapType];
					strcpy(tempType,"unknown");
					
				}
			}
	}

	if (strMapType!=NULL) strcpy(strMapType,tempType);
	
	if (tempMap==NULL) cout<<"CAUTION: The "<<strMapType<<" map is NULL data."<<endl;
	
	return tempMap;
}

double CMap::Average(int mapType)
{
	double average=0;
	int ii, jj;
	char strMapType[256];
	
	DENSITYMAP XY=DensityMapType(mapType, strMapType);

	for (ii=0;ii<m_width; ii++)
		for (jj=0;jj<m_height; jj++)
			average+=XY[ii][jj];
	average=average/(m_height*m_width);

	return average;
}

double CMap::NullAverage(int mapType)
{
	double average=0;
	int ii, jj;
	char strMapType[256];
	
	DENSITYMAP XY=DensityMapType(mapType, strMapType);

	for (ii=0;ii<m_width; ii++)
		for (jj=0;jj<m_height; jj++)
			if (m_indexMap[INDEX][ii][jj]==NODATA)	average+=XY[ii][jj];
	average=average/(m_height*m_width-m_grPixels);

	return average;
}

double CMap::PhaseAverage(int mapType)
{
	double average=0;
	int ii, jj;
	char strMapType[256];
	
	DENSITYMAP XY=DensityMapType(mapType, strMapType);

	for (ii=0;ii<m_width; ii++)
		for (jj=0;jj<m_height; jj++)
			if (m_indexMap[INDEX][ii][jj]!=NODATA)	average+=XY[ii][jj];
	average=average/(m_grPixels);

	return average;
}

double CMap::StandardDev(int mapType)
{
	double avg=Average(mapType);
	double stdDev=0;
	int ii, jj;
	char strMapType[256];
	
	DENSITYMAP XY=DensityMapType(mapType, strMapType);

	for (ii=0;ii<m_width; ii++)
		for (jj=0;jj<m_height; jj++)
			stdDev+=(XY[ii][jj]-avg)*(XY[ii][jj]-avg);
	stdDev=sqrt(stdDev/(m_height*m_width-1));

	return stdDev;
}

double CMap::PositiveStandardDev(int mapType)
{
	double avg=Average(mapType);
	double stdDev=0;
	int ii, jj;
	int count=0;
	char strMapType[256];
	
	DENSITYMAP XY=DensityMapType(mapType, strMapType);

	for (ii=0;ii<m_width; ii++)
		for (jj=0;jj<m_height; jj++)
			if (XY[ii][jj]-avg>0)
			{
                count++;
				stdDev+=sqrt((XY[ii][jj]-avg)*(XY[ii][jj]-avg));
			}
	stdDev=stdDev/count;

	return stdDev;
}

double CMap::NegativeStandardDev(int mapType)
{
	double avg=Average(mapType);
	double stdDev=0;
	int ii, jj;
	int count=0;
	char strMapType[256];
	
	DENSITYMAP XY=DensityMapType(mapType, strMapType);

	for (ii=0;ii<m_width; ii++)
		for (jj=0;jj<m_height; jj++)
			if (XY[ii][jj]-avg<0)
			{
                count++;
				stdDev+=-sqrt((XY[ii][jj]-avg)*(XY[ii][jj]-avg));
			}
	stdDev=stdDev/count;

	return stdDev;
}

double CMap::Fraction()
{
	double fraction=0;
	
	if (m_indexMap[INDEX]!=NULL && m_grPixels>=0 )
		fraction=(double)m_grPixels/(m_height*m_width);
	else 
		fraction=-1;

	return fraction;
}

double CMap::FindMaxDensity(int mapType)
{
	double max=0;
	int ii, jj;
	char strMapType[256];
	
	DENSITYMAP XY=DensityMapType(mapType, strMapType);

	for (ii=0;ii<m_width; ii++)
		for (jj=0;jj<m_height; jj++)
			if (max<XY[ii][jj]) max=XY[ii][jj];

	return max;
}

double CMap::FindMinDensity(int mapType)
{
	double min=1;
	int ii, jj;
	char strMapType[256];
	
	DENSITYMAP XY=DensityMapType(mapType, strMapType);

	for (ii=0;ii<m_width; ii++)
		for (jj=0;jj<m_height; jj++)
			if (min>XY[ii][jj]) min=XY[ii][jj];

	return min;
}

void CMap::PrintASCIIMap(int mapType)
{
	int ii, jj;
	char mn1[256], strMapType[256];
	
	DENSITYMAP XY=DensityMapType(mapType, strMapType);

	
	strcpy(mn1,m_mapName);
	strcat(mn1,"_");
	strcat(mn1,strMapType);
	strcat(mn1,"_map.asc");
	
	ofstream f1;
	
	f1.open(mn1);
	
	f1<<"ncols"<<"\t"<<m_width<<endl;
	f1<<"nrows"<<"\t"<<m_height<<endl;
	f1<<"xllcorner"<<"\t"<<0<<endl;
	f1<<"yllcorner"<<"\t"<<0<<endl;
	f1<<"cellsize"<<"\t"<<1<<endl;
	f1<<"NODATA_value"<<"\t"<<NODATA<<endl;

	for (jj=0; jj<m_height; jj++)
	{
		for (ii=0; ii<m_width; ii++)
			f1<<XY[ii][jj]<<"\t";
		f1<<endl;
	}

	f1.close();
}

void CMap::PrintGrASCIIMap(int mapType)
{
	int ii, jj;
	char mn1[256], strMapType[256];
	
	DENSITYMAP XY=DensityMapType(mapType, strMapType);

	
	strcpy(mn1,m_mapName);
	strcat(mn1,"_");
	strcat(mn1,strMapType);
	strcat(mn1,"_grain_map.asc");
//	cout<<mn1<<endl;
	
	ofstream f1;
	
	f1.open(mn1);
	
	f1<<"ncols"<<"\t"<<m_width<<endl;
	f1<<"nrows"<<"\t"<<m_height<<endl;
	f1<<"xllcorner"<<"\t"<<0<<endl;
	f1<<"yllcorner"<<"\t"<<0<<endl;
	f1<<"cellsize"<<"\t"<<1<<endl;
	f1<<"NODATA_value"<<"\t"<<NODATA<<endl;

	for (jj=0; jj<m_height; jj++)
	{
		for (ii=0; ii<m_width; ii++)
		{
			if (m_indexMap[INDEX][ii][jj]!=NODATA) f1<<XY[ii][jj]<<"\t";
			else f1<<NODATA<<"\t";
		}
		f1<<endl;
	}		

	f1.close();
}

void CMap::PrintGrainList()
{
//	int grNum=MAXGRNUM;
	int ii, jj;
	int grID;
//	int area[MAXGRNUM];
//	double value[MAXGRNUM];

//	DENSITYMAP XY=DensityMapType(mapType);
	
	for (jj=0; jj<m_height; jj++)
		for (ii=0; ii<m_width; ii++)
		{
			grID=m_indexMap[INDEX][ii][jj];
			if (grID!=NODATA)
			{ 
				grainList[grID]->m_density+=m_densityMap[DENSITY][ii][jj];
				grainList[grID]->m_size+=m_densityMap[SIZE][ii][jj];
				grainList[grID]->m_cluster+=m_densityMap[CLUSTER][ii][jj];
				grainList[grID]->m_freq+=m_densityMap[FREQ][ii][jj];
			}
		}
				
	for (ii=0; ii<MAXGRNUM; ii++)
		if (grainList[ii]!=NULL)
		{
			grainList[ii]->m_density=grainList[ii]->m_density/grainList[ii]->m_count;
			grainList[ii]->m_size=grainList[ii]->m_size/grainList[ii]->m_count;
			grainList[ii]->m_cluster=grainList[ii]->m_cluster/grainList[ii]->m_count;
			grainList[ii]->m_freq=grainList[ii]->m_freq/grainList[ii]->m_count;
		}

	char mn1[256];
	strcpy(mn1,m_mapName);
//	strcat(mn1,"_");
//	strcat(mn1,mapType);
	strcat(mn1,"_grain_list.txt");
//	cout<<mn1<<endl;
	
	ofstream f1;
	
	f1.open(mn1);

	f1<<"ID\tarea\tdensity\tsize\tcluster\tfreq\tDe\tNFreq"<<endl;
	
	for (ii=0; ii<MAXGRNUM; ii++)
		if (grainList[ii]!=NULL)
			f1<<ii<<"\t"
				<<grainList[ii]->m_count<<"\t"
				<<grainList[ii]->m_density<<"\t"
				<<grainList[ii]->m_size<<"\t"
				<<grainList[ii]->m_cluster<<"\t"
				<<grainList[ii]->m_freq<<"\t"
				<<(grainList[ii]->m_cluster-grainList[ii]->m_size)/grainList[ii]->m_density<<"\t"
				<<grainList[ii]->m_freq/m_grNum<<"\t"
				<<endl;

	f1.close();
}

void CMap::PrintList(int mapType)
{
	int ii, jj;
	int grID;
	char mn1[256], strMapType[256];
	
	DENSITYMAP XY=DensityMapType(mapType, strMapType);

	
	strcpy(mn1,m_mapName);
	strcat(mn1,"_");
	strcat(mn1,strMapType);
	strcat(mn1,"_list.txt");
//	cout<<mn1<<endl;
	
	ofstream f1;
	
	f1.open(mn1);
	
	f1<<"ID\tvalue"<<endl;
	for (jj=0; jj<m_height; jj++)
		for (ii=0; ii<m_width; ii++)
		{
			grID=m_indexMap[INDEX][ii][jj];
			f1<<grID<<"\t"<<XY[ii][jj]<<endl;
//	f1<<"Total\t"<<Average(mapType)<<endl;
//	f1<<"Phase\t"<<PhaseAverage(mapType)<<endl;
//	f1<<"Null\t"<<NullAverage(mapType)<<endl;
		}
	
	f1.close();
}

void CMap::Print2DList(int mapType)
{
	int ii, jj;
	char mn1[256], strMapType[256];
	
	DENSITYMAP XY=DensityMapType(mapType, strMapType);

	
	strcpy(mn1,m_mapName);
	strcat(mn1,"_");
	strcat(mn1,strMapType);
	strcat(mn1,"_map.txt");
//	cout<<mn1<<endl;
	
	ofstream f1;
	
	f1.open(mn1);
	
	for (jj=m_height-1; jj>-1; jj--)
	{
		for (ii=0; ii<m_width; ii++)
			f1<<XY[ii][jj]<<"\t";
		f1<<endl;
	}
	
	f1.close();
}

/* 
void CMap::PrintFreq()
{
	int ii, jj;
	int freq[256];
	int grayScale=0;

	for (ii=0;ii<256; ii++)
		freq[ii]=0;

	for (ii=0;ii<m_width; ii++)
		for (jj=0;jj<m_height; jj++)
		{
			grayScale=(int)floor((XY[ii][jj]*255)+0.5);
			freq[grayScale]++;
		}

	FILE *fp=fopen("Freq.txt","w");
	fprintf(fp, "Gray Scale\tFreq.\n");
	for (ii=0;ii<256; ii++)
	{
        fprintf(fp, "%5d\t%14d\n", ii, freq[ii]);
	}
	fclose(fp);
}

*/
